﻿using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using CloudShot.Logic;
using CloudShot.Utils;

namespace CloudShot.Editor.CanvasFigures
{
  public abstract class CanvasRectangleBase : CanvasObject
  {
    private Rectangle _rectangle;

    /// <summary>
    ///   Get number of handles
    /// </summary>
    public override int HandlesCount
    {
      get { return 8; }
    }

  

    public Rectangle Rectangle
    {
      get { return _rectangle; }
      set { _rectangle = value; }
    }

    public Color BackColor { get; set; }

    public byte BackgroundOpacity { get; set; }

    protected CanvasRectangleBase(int x, int y, int width, int height)
    {
      _rectangle.X = x;
      _rectangle.Y = y;
      _rectangle.Width = width;
      _rectangle.Height = height;

      BackColor = Color.White;
      BackgroundOpacity = 0;
      CurrentDragHandle = VertexType.RightBottom;
    }

    /// <summary>
    ///   Hit test.
    ///   Return value: -1 - no hit
    ///   0 - hit anywhere
    ///   > 1 - handle number
    /// </summary>
    /// <param name="point"></param>
    /// <returns></returns>
    public override int HitTest(Point point)
    {
      if (IsSelected)
      {
        for (int i = 1; i <= HandlesCount; i++)
        {
          if (GetHoverRectangle(i).Contains(point))
            return i;
        }
      }

      if (PointInObject(point))
        return 0;

      return -1;
    }

    public override Rectangle GetBoundingBox()
    {
      Rectangle rect = Rectangle.GetNormalizedRectangle();

      if (IsSelected)
      {
        int halfTrackerSize = TrackerSize / 2;
        rect.Inflate(halfTrackerSize, halfTrackerSize);

        //TODO remove this code. only for preview
        //we dragggin here
      }

      if (IsShowSize)
        rect.Inflate(100, 100);//now we cannot exactly determine label size

      return rect;
    }

    /// <summary>
    ///   Get cursor for the handle
    /// </summary>
    /// <param name="handleNumber"></param>
    /// <returns></returns>
    public override Cursor GetHandleCursor(int handleNumber)
    {
      switch (handleNumber)
      {
        case VertexType.LeftTop:
          return AppCursors.SizeNWSE;
        case VertexType.Top:
          return AppCursors.SizeNS;
        case VertexType.RightTop:
          return AppCursors.SizeNESW;
        case VertexType.Right:
          return AppCursors.SizeWE;
        case VertexType.RightBottom:
          return AppCursors.SizeNWSE;
        case VertexType.Bottom:
          return AppCursors.SizeNS;
        case VertexType.LeftBottom:
          return AppCursors.SizeNESW;
        case VertexType.Left:
          return AppCursors.SizeWE;
        default:
          return AppCursors.FigureOverCursor;
      }
    }

    /// <summary>
    ///   Move handle to new point (resizing)
    /// </summary>
    /// <param name="point"></param>
    /// <param name="handleNumber"></param>
    /// <param name="shiftPressed"></param>
    public override void MoveHandleTo(Point point, int handleNumber, bool shiftPressed)
    {
      int left = Rectangle.Left;
      int top = Rectangle.Top;
      int right = Rectangle.Right;
      int bottom = Rectangle.Bottom;

      switch (handleNumber)
      {
        case VertexType.LeftTop:
          left = point.X;
          top = point.Y;
          break;
        case VertexType.Top:
          top = point.Y;
          break;
        case VertexType.RightTop:
          right = point.X;
          top = point.Y;
          break;
        case VertexType.Right:
          right = point.X;
          break;
        case VertexType.RightBottom:
          right = point.X;
          bottom = point.Y;
          break;
        case VertexType.Bottom:
          bottom = point.Y;
          break;
        case VertexType.LeftBottom:
          left = point.X;
          bottom = point.Y;
          break;
        case VertexType.Left:
          left = point.X;
          break;
      }

      _rectangle.X = left;
      _rectangle.Y = top;
      _rectangle.Width = right - left;
      _rectangle.Height = bottom - top;

      if (!shiftPressed)
        return;

      //TODO refactor this later. this looks ugly
      switch (handleNumber)
      {
        case VertexType.LeftTop:
          {
            _rectangle = MakeSquare(_rectangle);
            _rectangle.X = right - _rectangle.Width;
            _rectangle.Y = bottom - _rectangle.Height;
            break;
          }

        case VertexType.RightBottom:
          {
            _rectangle = MakeSquare(_rectangle);
            break;
          }

        case VertexType.LeftBottom:
          {
            _rectangle = MakeSquare(_rectangle);
            _rectangle.X = right - _rectangle.Width;
            _rectangle.Y = top;
            break;
          }
        case VertexType.RightTop:
          {
            _rectangle = MakeSquare(_rectangle);
            _rectangle.X = left;
            _rectangle.Y = bottom - _rectangle.Height;
            break;
          }

        case VertexType.Bottom:
        case VertexType.Top:
          _rectangle.Width = SignMultiplier(_rectangle.Width) * Math.Abs(_rectangle.Height);
          break;

        case VertexType.Right:
        case VertexType.Left:
          _rectangle.Height = SignMultiplier(_rectangle.Height) * Math.Abs(_rectangle.Width);
          break;
      }
    }

    public Rectangle GetCurrentScreen(Rectangle[] screens, int dragHandle)
    {
      Point point = GetHandle(dragHandle);
      
      foreach (var screen in screens)
      {
        if (screen.Contains(point))
          return screen;
      }

      return screens[0];
    }

    public override bool IntersectsWith(Rectangle rectangle)
    {
      //return rectangle.Contains(Rectangle);
      return Rectangle.IntersectsWith(rectangle);
    }

    /// <summary>
    ///   Move object
    /// </summary>
    /// <param name="deltaX"></param>
    /// <param name="deltaY"></param>
    public override void Move(int deltaX, int deltaY)
    {
      _rectangle.X += deltaX;
      _rectangle.Y += deltaY;
    }

    /// <summary>
    ///   Normalize rectangle
    /// </summary>
    public override void Normalize()
    {
      _rectangle = _rectangle.GetNormalizedRectangle();
    }

    public override void DrawMarkup(Graphics graphics, Rectangle[] screens)
    {
      if (IsSelected)
      {
        var color = (BorderWidth > 0 && LineType != LineType.None) ? BorderColor : Color.FromArgb(59, 59, 59);

        using (var pen = new Pen(Color.FromArgb(150, color)))
        {
          var pattern = GetDashPattern();
          if (pattern != null)
          {
            //NOTE: it is necessary if figures overlap each other. 
            //Overlapped figures border will be drawn as thin line with same pattern as border.
            pen.DashPattern = pattern.Select(p => p * BorderWidth).ToArray();
          }

          graphics.DrawRectangle(pen, Rectangle);
        }
      }

      base.DrawMarkup(graphics, screens);

      if (IsShowSize)
        DrawSizeControl(graphics, screens);
    }

    protected virtual void DrawSizeControl(Graphics graphics, Rectangle[] screens)
    {
      SizeControl.Draw(graphics, Rectangle, Rectangle.Size, GetCurrentScreen(screens, CurrentDragHandle), CurrentDragHandle);
    }

    /// <summary>
    ///   Get handle point by 1-based number
    /// </summary>
    /// <param name="handleNumber"></param>
    /// <returns></returns>
    protected override Point GetHandle(int handleNumber)
    {
      return _rectangle.GetPointByHandle(handleNumber);
    }

    protected override bool PointInObject(Point point)
    {
      return _rectangle.Contains(point);
    }

    protected void SetCloneProperties(CanvasRectangleBase clone)
    {
      clone.Rectangle = Rectangle;
      clone.BackColor = BackColor;
      clone.BackgroundOpacity = BackgroundOpacity;
    }

    protected Brush CreateBackBrush()
    {
      return new SolidBrush(Color.FromArgb(BackgroundOpacity, BackColor));
    }

    private static Rectangle MakeSquare(Rectangle rectangle)
    {
      int absValue = Math.Min(Math.Abs(rectangle.Width), Math.Abs(rectangle.Height));
      rectangle.Height = absValue * SignMultiplier(rectangle.Height);
      rectangle.Width = absValue * SignMultiplier(rectangle.Width);
      return rectangle;
    }

    private static int SignMultiplier(int value)
    {
      if (value < 0)
        return -1;
      return 1;
    }
  }
}